<?php

namespace App\Console\Commands;

use App\Enums\AssetSourceType;
use App\Enums\AssetStatus;
use App\Enums\ProductType;
use App\Enums\TokenLockType;
use App\Enums\TokenStatus;
use App\Models\Airdrop;
use App\Models\Asset;
use App\Models\FrontendUser;
use App\Models\Product;
use App\Models\ProductToken;
use App\Services\WalletService;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Predis\Client;

class AirdropSyncCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'airdrop:sync';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '把空投的资产异步同步给用户';

    /**
     * Create a new command instance.
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $client = new Client();

        $ids = $client->get('airdrop_ids');
        // 查询已同步的资产ID列表
        $airdrops = Airdrop::where('status', 0)->where('type', ProductType::ISSUE)->when($ids, function ($q) use ($ids) {
            return $q->whereNotIn('id', json_decode($ids, true));
        })->limit(20)->get();

        $air_ids = array_column(json_decode(json_encode($airdrops), true), 'id');

        $client->set('airdrop_ids', json_encode($air_ids));

        $walletService = new WalletService();

        foreach ($airdrops as $airdrop) {
            $goods = Product::where('id', $airdrop->goods_id)->where('agent_id', $airdrop->agent_id)->first();

            if (empty($goods)) {
                $airdrop->status = 2;
                $airdrop->error_msg = '找不到商品';
                $airdrop->save();

                continue;
            }

            $contractAddress = $goods->contract_address;
            $quantity = $airdrop->number;
            $tokens = ProductToken::query()->where('product_id', $goods->id)
                ->where('status', TokenStatus::INIT)
                ->limit($quantity)->get();

            $productTokenIds = Arr::pluck($tokens, 'id');
            $tokenIds = Arr::pluck($tokens, 'token_id');

            if (count($tokenIds) < $quantity) {
                $airdrop->status = 2;
                $airdrop->error_msg = '库存不足';
                $airdrop->save();

                continue;
            }

            if (!empty($airdrop->tokenIds)) {
                continue;
            }

            $airdrop->tokenIds = json_encode($tokenIds);

            // 锁定
            ProductToken::query()->whereIn('id', $productTokenIds)->update([
                'lock_type' => TokenLockType::AIRDROP,
                'lock_refer_id' => $airdrop->id,
                'status' => TokenStatus::LOCKED,
            ]);

            $user = FrontendUser::where('mobile', $airdrop->mobile)->where('agent_id', $airdrop->agent_id)->first();

            try {
                $fromMobile = ''; // 默认使用商品发布时的收款方为付款方
                if ($goods->resale_user) {
                    $fromMobile = $goods->resale_user->mobile;
                }

                $transResult = $walletService->transfer(
                    $fromMobile,
                    $contractAddress,
                    $tokenIds,
                    $user->wallet_address
                );
                // 更新token状态
                foreach ($tokens as $token) {
                    $transHash = Arr::get($transResult, $token->token_id, 'trans_hash_not_return');
                    $token->status = TokenStatus::SOLD;
                    $token->save();

                    // 保存资产信息
                    $asset = new Asset();
                    $asset->user_id = $user->id;
                    $asset->source_type = AssetSourceType::AIRDROP;
                    $asset->source_id = $airdrop->id;
                    $asset->contract_address = $goods->contract_address;
                    $asset->token_id = $token->token_id;
                    $asset->trans_hash = $transHash;
                    $asset->asset_status = AssetStatus::HOLD;
                    $asset->save();
                }
                $airdrop->status = 1;
                $airdrop->save();
            } catch (\Exception $e) {
                ProductToken::query()->whereIn('id', $productTokenIds)->update([
                    'status' => TokenStatus::FAILED,
                ]);

                $airdrop->status = 2;
                $airdrop->error_msg = $e->getMessage();
                $airdrop->save();

                continue;
            }
        }

        return Command::SUCCESS;
    }
}
